#include "Scene.h"
#include "Common/PhysicsUtils.h"
#include "Player/EmptyPlayer.h"
#include "Player/HumanPlayer.h"


using namespace std;
using namespace core;
using namespace cmn;

int Scene::m_currentId = 0;

Scene::Scene() :
	m_camera( 0 )
{
	m_world = new b2World( b2Vec2( 0.0f, -9.8f ) );
}

Scene::Scene( Camera* camera ) :
	m_camera( camera )
{
	m_world = new b2World( b2Vec2( 0.0f, -9.8f ) );
}

Scene::~Scene() {
	delete m_world;
}

int Scene::CreateCreature() {
	Creature* creature = new Creature();
	m_creatures[++m_currentId] = creature;
	m_entities[m_currentId] = creature;
	return m_currentId;
}

void Scene::DeleteCreature( int creatureId ) {
	Creature* creature = m_creatures[creatureId];
	m_creatures.erase( creatureId );
	m_entities.erase( creatureId );
	delete creature;
}


int Scene::CreateDetail( int creatureId, const Transform& pos, const Transform& vel, const ReusableBodyDef* reusableBodyDef, const TextureInfo* texInfo ) {
	Creature* creature = m_creatures[creatureId];

	Detail* detail = new Detail( m_world, pos, vel, reusableBodyDef, texInfo );
	creature->AddPart( detail );

	m_details[++m_currentId] = detail;
	m_entities[m_currentId] = detail;
	return m_currentId;
}

Detail* Scene::GetDetail( int detailId ) { return m_details[detailId]; }

void Scene::DeleteDetail( int creatureId, int detailId ) {
	Creature* creature = m_creatures[creatureId];

	Detail* detail = m_details[detailId];
	creature->RemovePart( detail );

	m_details.erase( detailId );
	m_entities.erase( detailId );
	delete detail;
}


int Scene::CreateJunction( int creatureId, const Vec2& anchor, int detailAId, int detailBId, ReusableRotorDef* reusableRotorDef ) {
	Creature* creature = m_creatures[creatureId];

	Detail* detailA = m_details[detailAId];
	Detail* detailB = m_details[detailBId];

	b2RevoluteJointDef* jointDef = reusableRotorDef->GetBox2dRevoluteJointDef();

	jointDef->Initialize( detailA->GetBody(), detailB->GetBody(), ToB2Vec2( anchor ) );
	Junction* junction = new Junction( m_world, jointDef );

	creature->AddPart( junction );
	m_junctions[++m_currentId] = junction;
	m_entities[m_currentId] = junction;

	return m_currentId;
}

Junction* Scene::GetJunction( int junctionId ) {
	return m_junctions[junctionId];
}

void Scene::DeleteJunction( int creatureId, int junctionId ) {
	Creature* creature = m_creatures[creatureId];
	Junction* junction = m_junctions[junctionId];

	creature->RemovePart( junction );

	m_junctions.erase( junctionId );
	m_entities.erase( junctionId );
	delete junction;
}

int Scene::CreateObstacle( const Transform& pos, const ReusableBodyDef* reusableBodyDef, const TextureInfo* texInfo ) {
	Obstacle* obstacle = new Obstacle( m_world, pos, reusableBodyDef, texInfo );
	m_obstacles[++m_currentId] = obstacle;
	m_entities[m_currentId] = obstacle;
	return m_currentId;
}

Obstacle* Scene::GetObstacle( int obstacleId ) {
	return m_obstacles[obstacleId];
}

void Scene::DeleteObstacle( int obstacleId ) {
	Obstacle* obstacle = m_obstacles[obstacleId];
	m_obstacles.erase( obstacleId );
	m_entities.erase( obstacleId );
	delete obstacle;
}

IEntity* Scene::GetEntity( int entityId ) {
	return m_entities[entityId];
}

Part* Scene::GetPart( int partId ) {
	std::map<int, Detail*>::iterator dit = m_details.find( partId );
	if( dit != m_details.end() )
		return ( *dit ).second;

	std::map<int, Junction*>::iterator jit = m_junctions.find( partId );
	if( jit != m_junctions.end() )
		return ( *jit ).second;

	return 0;
}

void Scene::AddRule( int partId, const Rule& rule ) {
	Part* part = GetPart( partId );
	part->AddRule( rule );
}

void Scene::RemoveRule( int partId, const Rule& rule ) {
	Part* part = GetPart( partId );
	part->RemoveRule( rule );
}

void Scene::AddLink( int creatureId, int partAId, int partBId ) {
	Creature* creature = m_creatures[creatureId];
	Part* partA = GetPart( partAId );
	Part* partB = GetPart( partBId );
	creature->LinkParts( partA, partB );
}

void Scene::RemoveLink( int creatureId, int partAId, int partBId ) {
	Creature* creature = m_creatures[creatureId];
	Part* partA = GetPart( partAId );
	Part* partB = GetPart( partBId );
	creature->UnlinkParts( partA, partB );
}

int Scene::CreateHumanPlayer( int creatureId ) {
	Creature* creature = m_creatures[creatureId];
	HumanPlayer* human = new HumanPlayer( creature );
	core::Keyboard::AddListener( human );
	m_players[++m_currentId] = human;
	return m_currentId;
}

int Scene::CreateBotPlayer( int creatureId ) {
	Creature* creature = m_creatures[creatureId];
	EmptyPlayer* emptyPlayer = new EmptyPlayer( creature );
	m_players[++m_currentId] = emptyPlayer;
	return m_currentId;
}

void Scene::DeletePlayer( int playerId ) {
	IPlayer* player = m_players[playerId];
	m_players.erase( playerId );
	delete player;
}

void Scene::Update( float dt ) {
	m_world->Step( dt, 5, 5 );

	for( std::map<int, IEntity*>::iterator iter = m_entities.begin(); iter != m_entities.end(); iter++ ) {
		IEntity* entity = iter->second;
		entity->Update( dt );
	}

	m_camera->Update( dt );
}

void Scene::Render() {
	if( m_camera != 0 ) {
		core::Renderer::SetCamera( m_camera->GetPos(), m_camera->GetScale() );
	}
	Renderer::BeginDraw();

	for( std::map<int, IEntity*>::iterator iter = m_entities.begin(); iter != m_entities.end(); iter++ ) {
		IEntity* entity = iter->second;
		entity->Draw();
	}

	Renderer::EndDraw();
}

bool Scene::IsActive() {
	return !Keyboard::IsKeyPressed( KeyboardKey::Esc ) && Window::IsOpened();
}
